import requests
import time
import hashlib
import urllib.parse
import base64
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
from PIL import Image, ImageTk
import cv2
import numpy as np
import os
import ctypes
import platform
import ddddocr
import threading
from io import BytesIO
import json
from cryptography.fernet import Fernet
import uuid

class PutonghuaQueryUI:
    def __init__(self, root):
        self.root = root
        self.root.title("普通话成绩查询器")
        self.root.geometry("900x800")
        self.root.resizable(True, True)
        
        # 初始化OCR占位符
        self.ocr = None
        self.ocr1 = None
        self.ocr2 = None
        self.ocr3 = None
        
        # 存储当前的uid和验证码图片
        self.current_uid = None
        self.verify_image_data = None
        self.verify_image_enlarged = None
        
        # 配置文件路径
        self.config_file = "user_config.json"
        
        # 初始化加密密钥（基于MAC地址）
        self.init_encryption_key()
        
        # 加载用户配置
        self.load_user_config()
        
        self.setup_ui()
        
        # 异步初始化OCR引擎
        self.init_ocr_engines_async()
        
        # 从配置中加载用户信息
        self.name_var.set(str(self.saved_name) if self.saved_name else "")
        self.idcard_var.set(str(self.saved_idcard) if self.saved_idcard else "")
        self.stuid_var.set(str(self.saved_stuid) if self.saved_stuid else "")
    
    def init_ocr_engines_async(self):
        """异步初始化OCR引擎"""
        def init_ocr_thread():
            self.status_var.set("正在初始化OCR引擎...")
            self.get_verify_btn.config(state='disabled')
            self.re_recognize_btn.config(state='disabled')
            
            try:
                # 初始化OCR引擎
                self.ocr = ddddocr.DdddOcr()
                self.ocr1 = ddddocr.DdddOcr(beta=True)
                self.ocr2 = self.ocr
                self.ocr3 = self.ocr1
                
                # 初始化完成后更新UI
                self.root.after(0, self.on_ocr_initialized)
            except Exception as e:
                self.status_var.set(f"OCR引擎初始化失败: {str(e)}")
                # 即使初始化失败也启用按钮，让用户可以重试
                self.root.after(0, self.on_ocr_initialized)
        
        # 在单独的线程中初始化OCR引擎
        threading.Thread(target=init_ocr_thread, daemon=True).start()
    
    def on_ocr_initialized(self):
        """OCR引擎初始化完成后的回调"""
        if self.ocr and self.ocr1:
            self.status_var.set("OCR引擎初始化完成")
        else:
            self.status_var.set("OCR引擎初始化失败，请手动重试")
        
        # 启用验证码相关按钮
        self.get_verify_btn.config(state='normal')
        self.re_recognize_btn.config(state='normal')
        
        # 如果程序刚启动，延迟获取验证码
        if not self.current_uid:
            self.root.after(500, self.get_verify_code_async)
    
    def clear_inputs(self):
        """清空输入框"""
        self.name_var.set("")
        self.idcard_var.set("")
        self.stuid_var.set("")
        self.status_var.set("输入信息已清空")
        
    def init_encryption_key(self):
        """基于MAC地址初始化加密密钥"""
        try:
            # 获取MAC地址
            mac_address = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) for elements in range(0,2*6,2)][::-1])
            
            # 使用MAC地址和固定盐值生成256位密钥
            salt = "putonghua_query_tool_2025"  # 固定盐值
            combined = f"{mac_address}_{salt}"
            
            # 使用SHA256生成256位哈希
            hash_obj = hashlib.sha256(combined.encode('utf-8'))
            key_hash = hash_obj.digest()
            
            # 将256位哈希转为Fernet密钥格式（base64编码）
            self.encryption_key = base64.urlsafe_b64encode(key_hash)
            self.cipher_suite = Fernet(self.encryption_key)
            
        except Exception as e:
            print(f"加密初始化失败: {e}")
            # 如果获取MAC地址失败，使用默认密钥
            default_key = "default_putonghua_query_key_2025_backup_solution"
            key_hash = hashlib.sha256(default_key.encode('utf-8')).digest()
            self.encryption_key = base64.urlsafe_b64encode(key_hash)
            self.cipher_suite = Fernet(self.encryption_key)
    
    def encrypt_data(self, data):
        """加密数据"""
        try:
            if isinstance(data, str):
                data = data.encode('utf-8')
            return self.cipher_suite.encrypt(data).decode('utf-8')
        except Exception as e:
            print(f"加密失败: {e}")
            return data  # 如果加密失败，返回原数据
    
    def decrypt_data(self, encrypted_data):
        """解密数据"""
        try:
            if not encrypted_data:  # 空字符串直接返回
                return ""
            if isinstance(encrypted_data, str):
                encrypted_data = encrypted_data.encode('utf-8')
            decrypted = self.cipher_suite.decrypt(encrypted_data).decode('utf-8')
            return decrypted
        except Exception as e:
            print(f"解密失败: {e}")
            # 如果解密失败，返回空字符串而不是原数据
            return ""
        
    def load_user_config(self):
        """加载用户配置（加密存储）"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    # 解密用户信息，确保返回字符串
                    name_encrypted = config.get('name', '')
                    idcard_encrypted = config.get('idcard', '')
                    stuid_encrypted = config.get('stuid', '')
                    
                    # 如果是空值或者解密失败，返回空字符串
                    self.saved_name = self.decrypt_data(name_encrypted) if name_encrypted else ''
                    self.saved_idcard = self.decrypt_data(idcard_encrypted) if idcard_encrypted else ''
                    self.saved_stuid = self.decrypt_data(stuid_encrypted) if stuid_encrypted else ''
            else:
                self.saved_name = ''
                self.saved_idcard = ''
                self.saved_stuid = ''
        except Exception as e:
            print(f"加载配置失败: {e}")
            self.saved_name = ''
            self.saved_idcard = ''
            self.saved_stuid = ''
    
    def save_user_config(self):
        """保存用户配置（加密存储）"""
        try:
            # 加密用户信息
            config = {
                'name': self.encrypt_data(self.name_var.get()),
                'idcard': self.encrypt_data(self.idcard_var.get()),
                'stuid': self.encrypt_data(self.stuid_var.get())
            }
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存配置失败: {e}")
            
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky="nsew")
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        
        # 标题
        title_label = ttk.Label(main_frame, text="普通话成绩查询器", font=("Arial", 16, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20))
        
        # 输入框区域
        input_frame = ttk.LabelFrame(main_frame, text="查询信息", padding="10")
        input_frame.grid(row=1, column=0, columnspan=2, sticky="ew", pady=(0, 10))
        input_frame.columnconfigure(1, weight=1)
        
        # 用户名
        ttk.Label(input_frame, text="姓名:").grid(row=0, column=0, sticky="w", pady=5)
        self.name_var = tk.StringVar()
        self.name_entry = ttk.Entry(input_frame, textvariable=self.name_var, width=30)
        self.name_entry.grid(row=0, column=1, sticky="ew", pady=5, padx=(10, 0))
        
        # 身份证号
        ttk.Label(input_frame, text="身份证号:").grid(row=1, column=0, sticky="w", pady=5)
        self.idcard_var = tk.StringVar()
        self.idcard_entry = ttk.Entry(input_frame, textvariable=self.idcard_var, width=30)
        self.idcard_entry.grid(row=1, column=1, sticky="ew", pady=5, padx=(10, 0))
        
        # 准考证号
        ttk.Label(input_frame, text="准考证号:").grid(row=2, column=0, sticky="w", pady=5)
        self.stuid_var = tk.StringVar()
        self.stuid_entry = ttk.Entry(input_frame, textvariable=self.stuid_var, width=30)
        self.stuid_entry.grid(row=2, column=1, sticky="ew", pady=5, padx=(10, 0))
        
        # 验证码区域
        verify_frame = ttk.LabelFrame(main_frame, text="验证码", padding="10")
        verify_frame.grid(row=2, column=0, columnspan=2, sticky="ew", pady=(0, 10))
        verify_frame.columnconfigure(3, weight=1)
        
        # 验证码图片显示（放在最左边）
        self.verify_image_label = ttk.Label(verify_frame, text="正在获取验证码图片...")
        self.verify_image_label.grid(row=0, column=0, pady=5, padx=(0, 10))
        self.verify_image_label.bind("<Button-1>", self.show_enlarged_image)
        
        # 获取验证码按钮
        self.get_verify_btn = ttk.Button(verify_frame, text="获取验证码", command=self.get_verify_code_async)
        self.get_verify_btn.grid(row=0, column=1, pady=5, padx=(0, 5))
        
        # 重新识别按钮
        self.re_recognize_btn = ttk.Button(verify_frame, text="重新识别", command=self.recognize_verify_code)
        self.re_recognize_btn.grid(row=0, column=2, pady=5, padx=(0, 10))
        
        # OCR识别结果显示
        ttk.Label(verify_frame, text="OCR识别结果:").grid(row=1, column=0, sticky="w", pady=5)
        ocr_results_frame = ttk.Frame(verify_frame)
        ocr_results_frame.grid(row=1, column=1, columnspan=3, sticky="ew", pady=5, padx=(10, 0))
        ocr_results_frame.columnconfigure(1, weight=1)
        ocr_results_frame.columnconfigure(4, weight=1)
        
        # 第一排：OCR引擎1和2
        ttk.Label(ocr_results_frame, text="引擎1:").grid(row=0, column=0, sticky="w")
        self.ocr_result1_var = tk.StringVar()
        self.ocr_result1_entry = ttk.Entry(ocr_results_frame, textvariable=self.ocr_result1_var, width=12)
        self.ocr_result1_entry.grid(row=0, column=1, sticky="ew", padx=(5, 0))
        self.use_ocr1_btn = ttk.Button(ocr_results_frame, text="使用", command=lambda: self.use_ocr_result(1))
        self.use_ocr1_btn.grid(row=0, column=2, padx=(5, 10))
        
        ttk.Label(ocr_results_frame, text="引擎2:").grid(row=0, column=3, sticky="w")
        self.ocr_result2_var = tk.StringVar()
        self.ocr_result2_entry = ttk.Entry(ocr_results_frame, textvariable=self.ocr_result2_var, width=12)
        self.ocr_result2_entry.grid(row=0, column=4, sticky="ew", padx=(5, 0))
        self.use_ocr2_btn = ttk.Button(ocr_results_frame, text="使用", command=lambda: self.use_ocr_result(2))
        self.use_ocr2_btn.grid(row=0, column=5, padx=(5, 0))
        
        # 第二排：OCR引擎3和4
        ttk.Label(ocr_results_frame, text="引擎3:").grid(row=1, column=0, sticky="w", pady=(5, 0))
        self.ocr_result3_var = tk.StringVar()
        self.ocr_result3_entry = ttk.Entry(ocr_results_frame, textvariable=self.ocr_result3_var, width=12)
        self.ocr_result3_entry.grid(row=1, column=1, sticky="ew", padx=(5, 0), pady=(5, 0))
        self.use_ocr3_btn = ttk.Button(ocr_results_frame, text="使用", command=lambda: self.use_ocr_result(3))
        self.use_ocr3_btn.grid(row=1, column=2, padx=(5, 10), pady=(5, 0))
        
        ttk.Label(ocr_results_frame, text="引擎4:").grid(row=1, column=3, sticky="w", pady=(5, 0))
        self.ocr_result4_var = tk.StringVar()
        self.ocr_result4_entry = ttk.Entry(ocr_results_frame, textvariable=self.ocr_result4_var, width=12)
        self.ocr_result4_entry.grid(row=1, column=4, sticky="ew", padx=(5, 0), pady=(5, 0))
        self.use_ocr4_btn = ttk.Button(ocr_results_frame, text="使用", command=lambda: self.use_ocr_result(4))
        self.use_ocr4_btn.grid(row=1, column=5, padx=(5, 0), pady=(5, 0))
        
        # 手动输入验证码
        ttk.Label(verify_frame, text="验证码:").grid(row=2, column=0, sticky="w", pady=5)
        self.verify_code_var = tk.StringVar()
        self.verify_code_entry = ttk.Entry(verify_frame, textvariable=self.verify_code_var, width=20)
        self.verify_code_entry.grid(row=2, column=1, sticky="w", pady=5, padx=(10, 0))
        
        # 查询按钮和清空按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=3, column=0, columnspan=2, pady=10)
        
        self.query_btn = ttk.Button(button_frame, text="查询成绩", command=self.query_score_async)
        self.query_btn.grid(row=0, column=0, padx=(0, 10))
        
        self.clear_btn = ttk.Button(button_frame, text="清空", command=self.clear_inputs)
        self.clear_btn.grid(row=0, column=1)
        
        # 结果显示区域
        result_frame = ttk.LabelFrame(main_frame, text="查询结果", padding="10")
        result_frame.grid(row=4, column=0, columnspan=2, sticky="nsew", pady=(0, 10))
        result_frame.columnconfigure(0, weight=1)
        result_frame.rowconfigure(0, weight=1)
        main_frame.rowconfigure(4, weight=1)
        
        # 创建Treeview表格
        columns = ('字段', '값')
        self.result_tree = ttk.Treeview(result_frame, columns=columns, show='headings', height=10)
        self.result_tree.heading('字段', text='字段')
        self.result_tree.heading('값', text='값')
        self.result_tree.column('字段', width=150)
        self.result_tree.column('값', width=300)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(result_frame, orient=tk.VERTICAL, command=self.result_tree.yview)
        self.result_tree.configure(yscrollcommand=scrollbar.set)
        
        self.result_tree.grid(row=0, column=0, sticky="nsew")
        scrollbar.grid(row=0, column=1, sticky="ns")
        
        # 保留原来的文本框用于显示OCR信息
        self.result_text = scrolledtext.ScrolledText(result_frame, height=5, width=70)
        self.result_text.grid(row=1, column=0, columnspan=2, sticky="ew", pady=(10, 0))
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.grid(row=5, column=0, columnspan=2, sticky="ew")
    
    def show_enlarged_image(self, event=None):
        """显示放大的验证码图片"""
        if self.verify_image_enlarged is None:
            return
            
        # 创建新窗口显示放大图片
        enlarged_window = tk.Toplevel(self.root)
        enlarged_window.title("验证码放大图")
        enlarged_window.resizable(False, False)
        
        # 显示放大图片
        enlarged_label = ttk.Label(enlarged_window, image=self.verify_image_enlarged)
        enlarged_label.pack(padx=20, pady=20)
        
        # 窗口置顶
        enlarged_window.attributes('-topmost', True)
        enlarged_window.focus_force()
        
    def generate_sign(self, params, timestamp):
        """实现签名生成逻辑"""
        values_str = ''.join(str(v) for v in params.values())
        keys_str = ','.join(params.keys())
        params['pm'] = keys_str
        sign_str = urllib.parse.quote_plus(values_str + str(timestamp))
        mdsign = hashlib.md5(sign_str.encode()).hexdigest()
        return mdsign

    def set_headers(self, params):
        timestamp = int(time.time() * 1000)
        prams2 = params.copy()
        sign = self.generate_sign(prams2, timestamp)
        headers = {
            "Host": "zwfw.moe.gov.cn",
            "Connection": "keep-alive",
            "Accept": "*/*",
            "X-Requested-With": "XMLHttpRequest",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Origin": "https://zwfw.moe.gov.cn",
            "Referer": "https://zwfw.moe.gov.cn/mandarin/",
            "Accept-Encoding": "gzip, deflate, br, zstd",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Cookie": "_abfpc=8ac9c6c983680a8e99f2ec9c9e8894f995092ced_2.0; cna=00f31c0b21f62adb36945baa7546b739",
            "sec-ch-ua": '"Google Chrome";v="137", "Chromium";v="137", "Not/A)Brand";v="24"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-origin",
            "reqType": "3",
            "rn": str(timestamp),
            "sign": sign,
            "uid": ""
        }
        if 'pm' in prams2 and len(prams2['pm']) > 0:
            headers['pm'] = prams2['pm']
        return headers

    def get_verify_code_async(self):
        """异步获取验证码"""
        def get_verify_code_thread():
            self.status_var.set("正在获取验证码...")
            self.get_verify_btn.config(state='disabled')
            
            # 清空之前的OCR识别结果
            self.ocr_result1_var.set("")
            self.ocr_result2_var.set("")
            self.ocr_result3_var.set("")
            self.ocr_result4_var.set("")
            self.verify_code_var.set("")
            
            try:
                url = "https://zwfw.moe.gov.cn/eduSearch/prod/moe/govVerifyImage"
                params = {}
                headers = self.set_headers(params)
                
                response = requests.post(url, headers=headers)
                if response.status_code == 200:
                    json_data = response.json()
                    if json_data["code"] == "00":
                        self.current_uid = json_data["data"]["uid"]
                        image_data = json_data["data"]["imageUrl"].split(",")[1]
                        self.verify_image_data = base64.b64decode(image_data)
                        
                        # 显示验证码图片
                        self.display_verify_image()
                        
                        # 自动OCR识别验证码（确保每次都重新识别）
                        self.recognize_verify_code()
                        
                        self.status_var.set("验证码获取成功，OCR识别完成")
                    else:
                        self.status_var.set("获取验证码失败: " + json_data.get("message", "未知错误"))
                else:
                    self.status_var.set("网络请求失败")
            except Exception as e:
                self.status_var.set(f"获取验证码失败: {str(e)}")
            finally:
                self.get_verify_btn.config(state='normal')
        
        threading.Thread(target=get_verify_code_thread, daemon=True).start()
    
    def display_verify_image(self):
        """显示验证码图片"""
        try:
            # 确保有验证码图片数据
            if not self.verify_image_data:
                self.verify_image_label.config(text="无验证码图片")
                return
                
            # 从内存中加载图片
            image = Image.open(BytesIO(self.verify_image_data))
            # 放大图片以便查看
            image_small = image.resize((image.width * 2, image.height * 2), Image.NEAREST)
            photo = ImageTk.PhotoImage(image_small)
            
            # 保存放大版本用于点击显示
            image_large = image.resize((image.width * 6, image.height * 6), Image.NEAREST)
            self.verify_image_enlarged = ImageTk.PhotoImage(image_large)
            
            self.verify_image_label.config(image=photo, text="")
            # 使用after方法安全地设置图像引用
            self.root.after(0, lambda: setattr(self.verify_image_label, 'image', photo))
        except Exception as e:
            self.verify_image_label.config(text=f"图片显示失败: {str(e)}")
    
    def recognize_verify_code(self):
        """验证码OCR识别 - 强制重新识别两个引擎"""
        try:
            # 显示识别状态
            self.status_var.set("正在OCR识别验证码...")
            
            # 确保有验证码图片数据
            if not self.verify_image_data:
                self.ocr_result1_var.set("无验证码图片")
                self.ocr_result2_var.set("无验证码图片")
                self.ocr_result3_var.set("无验证码图片")
                self.ocr_result4_var.set("无验证码图片")
                return
            
            # 确保OCR引擎已初始化
            if not self.ocr or not self.ocr1 or not self.ocr2 or not self.ocr3:
                self.ocr_result1_var.set("OCR引擎未就绪")
                self.ocr_result2_var.set("OCR引擎未就绪")
                self.ocr_result3_var.set("OCR引擎未就绪")
                self.ocr_result4_var.set("OCR引擎未就绪")
                self.status_var.set("OCR引擎未就绪，请稍后重试")
                return
            
            # 使用四个OCR引擎识别
            ocr_results = []
            
            # 定义安全处理OCR结果的函数
            def safe_ocr_process(ocr_engine, image_data, preprocess_func=None):
                try:
                    # 应用预处理函数（如果提供）
                    processed_data = image_data
                    if preprocess_func:
                        processed_data = preprocess_func(image_data)
                    
                    # 设置范围并进行识别
                    if hasattr(ocr_engine, 'set_ranges'):
                        ocr_engine.set_ranges(6)
                    
                    # 根据是否有预处理选择不同的参数
                    if preprocess_func:
                        result = ocr_engine.classification(processed_data, png_fix=True, probability=True)
                    else:
                        result = ocr_engine.classification(image_data, probability=True)
                    
                    # 安全地提取结果
                    if isinstance(result, dict):
                        # 处理带概率的结果
                        if 'probability' in result and 'charsets' in result:
                            prob = result.get('probability', [])
                            charsets = result.get('charsets', [])
                            
                            # 确保我们有正确的数据结构
                            if isinstance(prob, list) and isinstance(charsets, list):
                                ocr_text = ""
                                for item in prob:
                                    if isinstance(item, list) and len(item) > 0:
                                        try:
                                            max_val = max(item)
                                            max_idx = item.index(max_val)
                                            if 0 <= max_idx < len(charsets):
                                                ocr_text += charsets[max_idx]
                                        except (ValueError, IndexError):
                                            pass
                                return ocr_text
                        # 如果是简单字符串结果
                        elif 'result' in result:
                            return str(result.get('result', ''))
                    
                    # 如果是直接的字符串结果
                    return str(result)
                except Exception as e:
                    return "识别失败"
            
            # 定义图像预处理函数
            def preprocess_for_ocr3(image_data):
                """为引擎3预处理图像"""
                image_array = np.frombuffer(image_data, np.uint8)
                img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
                if img is not None:
                    # 转为灰度图
                    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    # 高斯模糊去噪
                    blurred = cv2.GaussianBlur(gray, (3, 3), 0)
                    # 二值化处理
                    _, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
                    # 形态学操作去除小噪点
                    kernel = np.ones((2, 2), np.uint8)
                    cleaned = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
                    cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_OPEN, kernel)
                    # 将处理后的图像转换为字节数据
                    _, processed_image_data = cv2.imencode('.png', cleaned)
                    return processed_image_data.tobytes()
                return image_data
            
            def preprocess_for_ocr4(image_data):
                """为引擎4预处理图像"""
                image_array = np.frombuffer(image_data, np.uint8)
                img = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
                if img is not None:
                    # 转为灰度图
                    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    # 均值滤波去噪
                    denoised = cv2.blur(gray, (2, 2))
                    # 对比度增强
                    enhanced = cv2.convertScaleAbs(denoised, alpha=1.5, beta=10)
                    # 中值滤波进一步去噪
                    median_filtered = cv2.medianBlur(enhanced, 3)
                    # 锐化处理
                    kernel_sharpen = np.array([[-1,-1,-1],
                                             [-1, 9,-1],
                                             [-1,-1,-1]])
                    sharpened = cv2.filter2D(median_filtered, -1, kernel_sharpen)
                    # 将处理后的图像转换为字节数据
                    _, processed_image_data = cv2.imencode('.png', sharpened)
                    return processed_image_data.tobytes()
                return image_data
            
            # 引擎1识别
            ocr_result1 = safe_ocr_process(self.ocr, self.verify_image_data)
            ocr_results.append(ocr_result1)
            
            # 引擎2识别
            ocr_result2 = safe_ocr_process(self.ocr1, self.verify_image_data)
            ocr_results.append(ocr_result2)
            
            # 引擎3识别（带预处理）
            ocr_result3 = safe_ocr_process(self.ocr2, self.verify_image_data, preprocess_for_ocr3)
            ocr_results.append(ocr_result3)
            
            # 引擎4识别（带预处理）
            ocr_result4 = safe_ocr_process(self.ocr3, self.verify_image_data, preprocess_for_ocr4)
            ocr_results.append(ocr_result4)
            
            # 更新所有引擎的识别结果
            self.ocr_result1_var.set(ocr_result1)
            self.ocr_result2_var.set(ocr_result2)
            self.ocr_result3_var.set(ocr_result3)
            self.ocr_result4_var.set(ocr_result4)
            
            # 选择最佳结果自动填入验证码输入框
            valid_results = [(i+1, result) for i, result in enumerate(ocr_results) if result != "识别失败" and result != "图像处理失败" and len(result) > 0]
            if valid_results:
                # 优先选择长度最合适的结果（通常验证码是4-6位）
                best_engine, best_result = max(valid_results, key=lambda x: len(x[1]) if 4 <= len(x[1]) <= 6 else 0)
                if best_result:
                    recommended_engine = f"引擎{best_engine}"
                else:
                    # 如果没有合适长度的，选择第一个有效结果
                    best_engine, best_result = valid_results[0]
                    recommended_engine = f"引擎{best_engine}(备选)"
            else:
                best_result = ocr_result1  # 默认使用引擎1结果
                recommended_engine = "引擎1(默认)"
                
            self.verify_code_var.set(best_result)
            
            # 在结果区域显示OCR识别信息
            self.result_text.insert(tk.END, f"新验证码OCR识别完成:\n")
            self.result_text.insert(tk.END, f"引擎1识别: {ocr_result1}\n")
            self.result_text.insert(tk.END, f"引擎2识别: {ocr_result2}\n")
            self.result_text.insert(tk.END, f"引擎3识别: {ocr_result3}\n")
            self.result_text.insert(tk.END, f"引擎4识别: {ocr_result4}\n")
            self.result_text.insert(tk.END, f"推荐使用: {best_result} (来自{recommended_engine})\n")
            self.result_text.insert(tk.END, "-" * 30 + "\n")
            self.result_text.see(tk.END)
            
            self.status_var.set("OCR识别完成")
            
        except Exception as e:
            error_msg = f"识别失败: {str(e)}"
            self.ocr_result1_var.set(error_msg)
            self.ocr_result2_var.set(error_msg)
            self.status_var.set("OCR识别失败")
    
    def use_ocr_result(self, engine_num):
        """使用OCR识别结果填入验证码输入框"""
        if engine_num == 1:
            result = self.ocr_result1_var.get()
        elif engine_num == 2:
            result = self.ocr_result2_var.get()
        elif engine_num == 3:
            result = self.ocr_result3_var.get()
        else:  # engine_num == 4
            result = self.ocr_result4_var.get()
            
        # 清空验证码输入框并填入新的识别结果
        self.verify_code_var.set("")
        self.verify_code_var.set(result)
        self.status_var.set(f"已使用OCR引擎{engine_num}的识别结果: {result}")
    
    def query_score_async(self):
        """异步查询成绩"""
        def query_score_thread():
            self.status_var.set("正在查询成绩...")
            self.query_btn.config(state='disabled')
            
            try:
                # 检查必要信息
                if not self.current_uid:
                    self.root.after(0, lambda: messagebox.showerror("错误", "请先获取验证码"))
                    return
                
                name = self.name_var.get().strip()
                idcard = self.idcard_var.get().strip()
                stuid = self.stuid_var.get().strip()
                verify_code = self.verify_code_var.get().strip()
                
                if not all([name, idcard, stuid, verify_code]):
                    self.root.after(0, lambda: messagebox.showerror("错误", "请填写完整信息"))
                    return
                
                # 保存用户配置
                self.save_user_config()
                
                # 查询成绩
                result = self.query_student_score(name, idcard, stuid, self.current_uid, verify_code)
                
                # 显示结果
                self.root.after(0, lambda: self.display_query_result(result))
                
            except Exception as e:
                self.status_var.set(f"查询失败: {str(e)}")
                self.result_text.insert(tk.END, f"查询出错: {str(e)}\n\n")
                self.result_text.see(tk.END)
            finally:
                self.query_btn.config(state='normal')
        
        threading.Thread(target=query_score_thread, daemon=True).start()
    
    def query_student_score(self, name, idcard, stuid, uid, verify_code):
        """查询学生成绩"""
        url = "https://zwfw.moe.gov.cn/eduSearch/prod/moe/verify/studentScore"
        
        params = {
            "name": name,
            "idCard": idcard,
            "stuId": stuid,
            "uid": uid,
            "verifyCode": verify_code
        }
        
        headers = self.set_headers(params)
        
        # 打印调试信息
        print(f"查询参数: {params}")
        print(f"请求头: {dict(headers)}")
        
        response = requests.post(url, headers=headers, data=params)
        print(f"响应状态码: {response.status_code}")
        print(f"响应内容: {response.text}")
        
        return response.json()
    
    def display_query_result(self, json_data):
        """显示查询结果"""
        # 清空表格
        for item in self.result_tree.get_children():
            self.result_tree.delete(item)
        
        # 在文本框显示查询时间
        self.result_text.insert(tk.END, "=" * 50 + "\n")
        self.result_text.insert(tk.END, f"查询时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
        self.result_text.insert(tk.END, "=" * 50 + "\n\n")
        self.result_text.see(tk.END)
        
        if "data" in json_data and json_data["data"]:
            data = json_data["data"]
            # 成功查询，使用表格显示
            self.result_tree.insert('', 'end', values=('姓名', data.get('name', 'N/A')))
            self.result_tree.insert('', 'end', values=('考试级别', data.get('level', 'N/A')))
            self.result_tree.insert('', 'end', values=('考试成绩', data.get('score', 'N/A')))
            self.result_tree.insert('', 'end', values=('性别', data.get('gender', 'N/A')))
            self.result_tree.insert('', 'end', values=('准考证号', data.get('stuId', 'N/A')))
            self.result_tree.insert('', 'end', values=('身份证号', data.get('idCard', 'N/A')))
            self.result_tree.insert('', 'end', values=('考试中心ID', data.get('centId', 'N/A')))
            
            self.status_var.set("查询成功")
            messagebox.showinfo("成功", f"查询成功！\n姓名: {data.get('name', 'N/A')}\n成绩: {data.get('score', 'N/A')}")
            
            #重新获取验证码
            self.get_verify_code_async()
            
        elif json_data.get("code") == "00":
            self.result_tree.insert('', 'end', values=('查询结果', '查询不到该学生信息'))
            self.status_var.set("查询不到信息")
            messagebox.showwarning("没有结果", "查询不到该学生信息！")
            
            #重新获取验证码
            self.get_verify_code_async()
        else:
            # 错误信息显示在表格中
            self.result_tree.insert('', 'end', values=('错误代码', json_data.get('code', 'N/A')))
            self.result_tree.insert('', 'end', values=('错误信息', json_data.get('message', 'N/A')))
            
            # 弹框提示错误
            error_msg = f"查询失败\n错误代码: {json_data.get('code', 'N/A')}\n错误信息: {json_data.get('message', 'N/A')}"
            if json_data.get("code") == "06":
                error_msg += "\n\n提示: 验证码错误，请重新获取验证码"
            
            messagebox.showerror("查询失败", error_msg)
            self.status_var.set("查询失败")
            
        

def main():
    root = tk.Tk()
    app = PutonghuaQueryUI(root)
    root.mainloop()

if __name__ == "__main__":
    main()